/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 input_manager.cc                                          VLC Gtkmmm gui module
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Copyright © 2006-2008 the VideoLAN team

 Authors: David GUGLIELMI <raxxx.fr@gmail.com>
          David LARROQUE <david.larroque@gmail.com>

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 PARTICULAR PURPOSE. See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 Street, Fifth Floor, Boston MA 02110-1301, USA.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gtkmm.hh"
#include "input_manager.hh"
#include "dialogs_provider.hh"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int change_spu (vlc_object_t *p_this, const char *var,\
                       vlc_value_t o, vlc_value_t n, void *param);
static int change_teletext (vlc_object_t *p_this, const char *var,\
                            vlc_value_t o, vlc_value_t n, void *param);
static int item_changed (vlc_object_t *, const char *,\
                         vlc_value_t, vlc_value_t, void *);
static int pl_item_changed (vlc_object_t *, const char *,\
                            vlc_value_t, vlc_value_t, void *);
static int interface_changed (vlc_object_t *, const char *,\
                              vlc_value_t, vlc_value_t, void *);
static int item_state_changed (vlc_object_t *, const char *,\
                               vlc_value_t, vlc_value_t, void *);
static int item_rate_changed (vlc_object_t *, const char *,\
                              vlc_value_t, vlc_value_t, void *);
static int item_title_changed (vlc_object_t *, const char *,\
                               vlc_value_t, vlc_value_t, void *);
static int volume_changed (vlc_object_t *, const char *,\
                           vlc_value_t, vlc_value_t, void *);

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// InputManager implementation
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The Input Manager can be the main one around the playlist
// But can also be used for VLM dialog or similar
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputManager::InputManager (intf_thread_t *_p_intf)
{
  i_old_playing_status = END_S;
  old_name = "";
  art_url = "";
  p_input = NULL;
  i_rate = 0;
  i_input_id = 0;
  b_transparent_telextext = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputManager::~InputManager ()
{
  del_input ();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Define the Input used. Add the callbacks on input p_input is yield once here
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::set_input (input_thread_t *_p_input)
{
  del_input();
  p_input = _p_input;
  if (p_input && !(p_input->b_dead || !vlc_object_alive (p_input)))
  {
    vlc_object_yield (p_input);
//    FIXME emit status_changed (PLAYING_S);
    update_meta ();
    update_art ();
    update_spu ();
    update_teletext ();
    update_navigation ();
    add_callbacks ();
    i_input_id = input_GetItem (p_input)->i_id;
  }
  else
  {
    p_input = NULL;
    i_input_id = 0;
//    FIXME emit rate_changed (INPUT_RATE_DEFAULT);
//    FIXME emit input_unset ();
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// delete Input if it ever existed.
// Delete the callbacls on input p_input is released once here 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::del_input ()
{
    if (p_input)
    {
        del_callbacks ();
        i_old_playing_status = END_S;
        i_input_id = 0;
        old_name = "";
        art_url = "";
//        FIXME emit position_updated (0.0, 0 ,0);
//        FIXME emit status_changed (END_S);
//        FIXME emit name_changed ("");
//        FIXME emit art_changed ("");
//        FIXME emit rate_changed (INPUT_RATE_DEFAULT);
        vlc_object_release (p_input);
        p_input = NULL;
        update_spu ();
        update_teletext ();
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add the callbacks on Input. Self explanatory
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::add_callbacks ()
{
  // chapter, programs, audio-delay, spu-delay, bookmark, position, time,
  // length are included in intf-change
  var_AddCallback (p_input, "state", item_state_changed, this);
  var_AddCallback (p_input, "spu-es", change_spu, this);
  var_AddCallback (p_input, "teletext-es", change_teletext, this);
  var_AddCallback (p_input, "rate-change", item_rate_changed, this);
  var_AddCallback (p_input, "title", item_title_changed, this);
  // for timers update
  var_AddCallback (p_input, "intf-change", interface_changed, this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Delete the callbacks on Input. Self explanatory
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::del_callbacks ()
{
  var_DelCallback (p_input, "spu-es", change_spu, this);
  var_DelCallback (p_input, "teletext-es", change_teletext, this);
  var_DelCallback (p_input, "state", item_state_changed, this );
  var_DelCallback (p_input, "rate-change", item_rate_changed, this);
  var_DelCallback (p_input, "title", item_title_changed, this );
  var_DelCallback (p_input, "intf-change", interface_changed, this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Convert the event from the callbacks in actions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO void InputManager::custom_event(
// TODO add Custom event
// TODO
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_position ()
{
    /* Update position */
    int i_length, i_time; /* Int is enough, since we store seconds */
    float f_pos;
    i_length = var_GetTime (p_input , "length") / 1000000;
    i_time = var_GetTime (p_input , "time") / 1000000;
    f_pos = var_GetFloat (p_input , "position");
//    FIXME emit position_updated (f_pos, i_time, i_length);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_navigation ()
{
  // Update navigation status
  vlc_value_t val; val.i_int = 0;
  var_Change (p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL);
  if (val.i_int > 0)
  {
    val.i_int = 0;
    var_Change (p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL);
//    FIXME emit navigation_changed ((val.i_int > 0) ? 1 : 2);
  }
  else
  {
//    FIXME emit navigation_changed (0);
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_status ()
{
  // Update playing status
  vlc_value_t val; val.i_int = 0;
  var_Get (p_input, "state", &val);
  if (i_old_playing_status != val.i_int)
  {
    i_old_playing_status = val.i_int;
//    FIXME emit status_changed (val.i_int);
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_rate ()
{
  // Update Rate
  int i_new_rate = var_GetInteger (p_input, "rate");
  if (i_new_rate != i_rate)
  {
    i_rate = i_new_rate;
    // Update rate
//    FIXME emit rate_changed (i_rate);
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_meta ()
{
  // Update text, name and nowplaying
  Glib::ustring text;

  char *psz_name = input_item_GetTitle (input_GetItem (p_input));
  if (EMPTY_STR (psz_name))
  {
    free (psz_name);
    psz_name = input_item_GetName (input_GetItem (p_input));
  }

  char *psz_nowplaying = input_item_GetNowPlaying (input_GetItem (p_input));
  if (!EMPTY_STR (psz_nowplaying))
  {
    //FIXME text.sprintf ("%s - %s", psz_nowplaying, psz_name);
  }
  else
  {
    char *psz_artist = input_item_GetArtist (input_GetItem (p_input));
    if (!EMPTY_STR (psz_artist))
    {
      //FIXME text.sprintf ("%s - %s", psz_artist, psz_name);
    }
    else
    {
      //FIXME text.sprintf( "%s", psz_name );
    }
    free (psz_artist);
  }
  free (psz_name);
  free (psz_nowplaying);

  if (old_name != text)
  {
//    FIXME emit name_changed (text);
    old_name = text;
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
InputManager::has_audio ()
{
  if (has_input ())
  {
    vlc_value_t val;
    var_Change (p_input, "audio-es", VLC_VAR_CHOICESCOUNT, &val, NULL);
    return val.i_int > 0;
  }
  return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool InputManager::has_video ()
{
  if (has_input ())
  {
    vlc_value_t val;
    var_Change (p_input, "video-es", VLC_VAR_CHOICESCOUNT, &val, NULL);
    return val.i_int > 0;
  }
  return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputManager::update_spu ()
{
  update_teletext ();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_teletext()
{
  if (has_input ())
    telex_toggle (var_GetInteger (p_input, "teletext-es") >= 0);
  else
    telex_toggle (false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::update_art ()
{
  // Update Art meta
  Glib::ustring url;
  char *psz_art = input_item_GetArtURL (input_GetItem (p_input));
  // FIXME url.sprintf("%s", psz_art);
  free (psz_art);
  if (art_url != url)
  {
    // FIXME art_url = url.replace ("file://", Glib::ustring (""));
    // FIXME Taglib seems to define a attachment but don't work yet
    // FIXME art_url = url.replace ("attachment://", Glib::ustring (""));
    // FIXME emit art_changed (art_url);
    // FIXME msg_Dbg (p_intf, "Art:  %s", qtu(art_url));
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/* User update of the slider */
void InputManager::slider_update (float new_pos)
{
  if (has_input ())
    var_SetFloat (p_input, "position", new_pos);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// User toggle_play_pause
void
InputManager::toggle_play_pause ()
{
  vlc_value_t state;
  var_Get (p_input, "state", &state);
  state.i_int = (state.i_int != PLAYING_S) ? PLAYING_S : PAUSE_S;
  var_Set (p_input, "state", state);
//  emit status_changed (state.i_int);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::section_prev ()
{
  if (has_input ())
  {
    int i_type = var_Type (p_input, "next-chapter");
    vlc_value_t val;
    val.b_bool = true;
    var_Set (p_input,\
             (i_type & VLC_VAR_TYPE) != 0 ? "prev-chapter":"prev-title",\
             val);
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::section_next ()
{
  if (has_input ())
  {
    int i_type = var_Type (p_input, "next-chapter");
    vlc_value_t val;
    val.b_bool = true;
    var_Set (p_input,\
             (i_type & VLC_VAR_TYPE) != 0 ? "next-chapter":"next-title",\
             val);
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::section_menu ()
{
  if (has_input ())
  {
    vlc_value_t val; val.i_int = 2;
    var_Set (p_input, "title  0", val);
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::telex_goto_page (int page)
{
  if (has_input ())
  {
    const int i_teletext_es = var_GetInteger (p_input, "teletext-es");
    const int i_spu_es = var_GetInteger (p_input, "spu-es");

    if (i_teletext_es >= 0 && i_teletext_es == i_spu_es)
    {
      vlc_object_t *p_vbi;
      p_vbi = (vlc_object_t *) vlc_object_find_name (p_input,\
                                                     "zvbi", FIND_ANYWHERE);
      if (p_vbi)
      {
        var_SetInteger (p_vbi, "vbi-page", page);
        vlc_object_release (p_vbi);
      }
    }
  }
//  FIXME emit set_new_telex_page (page);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::telex_toggle (bool b_enabled)
{
  int i_page = 100;

  if (has_input ())
  {
    const int i_teletext_es = var_GetInteger (p_input, "teletext-es");
    const int i_spu_es = var_GetInteger (p_input, "spu-es");

    b_enabled = i_teletext_es >= 0;
    if (b_enabled && i_teletext_es == i_spu_es)
    {
      vlc_object_t *p_vbi;
      p_vbi = (vlc_object_t *) vlc_object_find_name (p_input,\
                                                     "zvbi",\
                                                     FIND_ANYWHERE);
      if (p_vbi)
      {
        i_page = var_GetInteger (p_vbi, "vbi-page");
        vlc_object_release (p_vbi);
        i_page = b_enabled ? i_page : 0;
        telex_goto_page (i_page);
      }
    }
  }
//  FIXME emit teletext_enabled (b_enabled);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::telex_toggle_buttons ()
{
  if (has_input ())
  {
    const int i_teletext_es = var_GetInteger (p_input, "teletext-es");
    if (i_teletext_es >= 0)
    {
      const int i_spu_es = var_GetInteger (p_input, "spu-es");

      if (i_teletext_es == i_spu_es)
        var_SetInteger (p_input, "spu-es", -1);
      else
        var_SetInteger (p_input, "spu-es", i_teletext_es);

//      FIXME emit toggle_telex_buttons();
    }
  }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::telex_set_transparency ()
{
  if (has_input ())
  {
    vlc_object_t *p_vbi;
    p_vbi = (vlc_object_t *) vlc_object_find_name (p_input,\
                                                   "zvbi", FIND_ANYWHERE);
    if (p_vbi)
    {
      var_SetBool (p_vbi, "vbi-opaque", b_transparent_telextext);
      b_transparent_telextext = !b_transparent_telextext;
      vlc_object_release (p_vbi);
    }
  }
//  FIXME emit toggle_telex_transparency ();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::slower ()
{
  if (has_input ())
    var_SetVoid (p_input, "rate-slower");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::faster ()
{
  if (has_input ())
    var_SetVoid (p_input, "rate-faster");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::normal_rate ()
{
  if (has_input ())
    var_SetInteger (p_input, "rate", INPUT_RATE_DEFAULT);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
InputManager::set_rate (int new_rate)
{
  if (has_input ())
    var_SetInteger (p_input, "rate", new_rate);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// MainInputManager implementation. Wrap an input manager and take care of
// updating the main playlist input. Used in the main playlist Dialog

MainInputManager * MainInputManager::instance = NULL;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MainInputManager::MainInputManager (intf_thread_t *_p_intf) : p_intf (_p_intf)
{
  p_input = NULL;
  im = new InputManager (p_intf); // FIXME it was (this, p_intf);

  //var_AddCallback (THEPL, "item-change", pl_item_changed, this);
  var_AddCallback (THEPL, "item-change", item_changed, im);
  var_AddCallback (THEPL, "playlist-current", pl_item_changed, this);
  var_AddCallback (THEPL, "activity", pl_item_changed, this);
  var_AddCallback (p_intf->p_libvlc, "volume-change", volume_changed, this);

  // No necessary, I think TODO REMOVE ME at the end
  //var_AddCallback (THEPL, "intf-change", item_changed, im);

  // Warn our embedded IM about input changes
  //FIXME CONNECT (this, input_changed (input_thread_t *),im,\
  //                                     setInput (input_thread_t *));

  // emit check if playlist has allready started playing
  vlc_value_t val;
  var_Change (THEPL, "playlist-current", VLC_VAR_CHOICESCOUNT, &val, NULL);
  //TODO event !!!
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MainInputManager::~MainInputManager ()
{
  if (p_input)
  {
    var_DelCallback (p_input, "state", pl_item_changed, this);
    vlc_object_release (p_input);
//    FIXME emit input_changed (NULL);
  }
  var_DelCallback (p_intf->p_libvlc, "volume-change", volume_changed, this);
  var_DelCallback (THEPL, "activity", pl_item_changed, this);
  var_DelCallback (THEPL, "item-change", item_changed, im);
  //var_DelCallback (THEPL, "item-change", pl_item_changed, this);
  var_DelCallback (THEPL, "playlist-current", pl_item_changed, this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// TODO
// TODO MainInputManager::customEvent(
// TODO
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Playlist Control functions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MainInputManager::stop ()
{
  playlist_Stop (THEPL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MainInputManager::next ()
{
  playlist_Next (THEPL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MainInputManager::prev ()
{
  playlist_Prev (THEPL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
MainInputManager::toggle_play_pause ()
{
  if (p_input == NULL)
  {
    playlist_Play (THEPL);
    return;
  }
  get_im ()->toggle_play_pause ();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
MainInputManager::teletext_state ()
{
  im = get_im ();
  if (im->has_input ())
  {
    const int i_teletext_es = var_GetInteger (get_input (), "teletext-es");
    const int i_spu_es = var_GetInteger (get_input (), "spu-es");

    return i_teletext_es >= 0 && i_teletext_es == i_spu_es;
  }
  return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Static callbacks
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// IM
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
interface_changed (vlc_object_t *p_this, const char *psz_var,\
                   vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
item_state_changed (vlc_object_t *p_this, const char *psz_var,\
                    vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
item_rate_changed (vlc_object_t *p_this, const char *psz_var,\
                              vlc_value_t oldval, vlc_value_t newval,\
                              void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
item_title_changed (vlc_object_t *p_this, const char *psz_var,\
                    vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
item_changed (vlc_object_t *p_this, const char *psz_var,\
              vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
change_spu (vlc_object_t *p_this, const char *var, vlc_value_t o,\
            vlc_value_t n, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
change_teletext (vlc_object_t *p_this, const char *var,\
                 vlc_value_t o, vlc_value_t n, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// MIM
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
pl_item_changed (vlc_object_t *p_this, const char *psz_var,\
                 vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static int
volume_changed (vlc_object_t *p_this, const char *psz_var,\
                vlc_value_t oldval, vlc_value_t newval, void *param)
{
  //FIXME Fill
  return VLC_SUCCESS;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
